Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: potential data disclosure is observed in WasmEdge Rust SDK #101

Open
candymate opened this issue Apr 19, 2024 · 4 comments
Open

bug: potential data disclosure is observed in WasmEdge Rust SDK #101

candymate opened this issue Apr 19, 2024 · 4 comments
Assignees

Comments

@candymate
Copy link

candymate commented Apr 19, 2024

Quick notice

The WasmEdge team confirmed that this can be public, so I'm uploading this as a public issue.

Description

There is a potential data leakage between WasmValue and WasmEdge_Value which possibly disclose address base of some mmap'ed map. Since the data is represented in i128 in WasmEdge_Value, it may contain uninitialized values on the high bits of the value. For example, if a WASM program that returns a single f32 constant of 1.0 (0x3f800000) is executed using the Rust SDK, data disclosures appear as [WasmValue { ctx: WasmEdge_Value { Value: 93910525280256, Type: 125 }, ty: F32 }], which the hex value is 0x5569_3f800000. (i.e., 0x5569 is leaked)

pub struct WasmEdge_Value {
  pub Value: uint128_t,
  pub Type: WasmEdge_ValType,
}
(module
  (type (;0;) (func (result f32)))
  (func (;0;) (type 0) (result f32)
    f32.const 0x1p+0 (;=1;))
  (export "main" (func 0)))

It appears the value changes each time the function is executed. My guess is that the disclosed value points to a mmap'ed memory region used in the execution of the program, possibly the pointer to the region. If this is true, the attackers might be able to use the disclosed value to find the base address of the region, possibly elaborate it into an arbitrary code execution if they find and combine an arbitrary write vulnerability.

Current State

The data disclosure happens across all optimization levels (O0~Oz). The disclosed data changes every time the program is executed. One example would be the following: (execution with the wasm program above)

[WasmValue { ctx: WasmEdge_Value { Value: 93910525280256, Type: 125 }, ty: F32 }]

The data is also disclosed in non-AOT mode. However, the disclosed data is always 0x10000000.

Expected State

There shouldn't be any disclosed data. The value should be clearly 0x3f800000.

Versions

  • WasmEdge 0.13.5
  • wasmedge-sdk (rust) 0.13.2, with feature "aot"

PoC Code

Run the following Rust code with the wasm program above:

use wasmedge_sdk::config::CommonConfigOptions;
use wasmedge_sdk::config::CompilerConfigOptions;
use wasmedge_sdk::config::ConfigBuilder;
use wasmedge_sdk::types::Val;
use wasmedge_sdk::Compiler;
use wasmedge_sdk::CompilerOptimizationLevel;
use wasmedge_sdk::CompilerOutputFormat;
use wasmedge_sdk::LogManager;
use wasmedge_sdk::Module;
use wasmedge_sdk::VmBuilder;
use anyhow::{bail, Error};

fn main() -> Result<(), Error> {
    LogManager::log_off();
    
    let config = ConfigBuilder::new(CommonConfigOptions::default())
        .with_compiler_config(
            CompilerConfigOptions::default()
                .optimization_level(CompilerOptimizationLevel::O0) // change here for optimization level
                .out_format(CompilerOutputFormat::Native))
        .build()?;
    let compiler = Compiler::new(Some(&config))?;
    let aot_file_path = compiler.compile_from_file("test.wasm", "aot", ".")?;
    let module = Module::from_file(Some(&config), aot_file_path)?;
    let vm = VmBuilder::new().with_config(config).build()?.register_module(None, module)?;

    let instance = vm.active_module()?;
    let main = match instance.func_names() {
        Some(x) => instance.func(x[0].clone())?,
        None => bail!("There is no exported function"),
    };
    
    let params: [Val; 0] = Default::default();
    match main.run(vm.executor(), params.into_iter().map(|x| x.into())) {
        Ok(results) => println!("{:?}", results),
        Err(_e) => println!("Error"),
    }

    Ok(())
}
@L-jasmine
Copy link
Collaborator

@hydai

@hydai
Copy link
Member

hydai commented Apr 19, 2024

Hi @q82419
According to the report, the issue could be more general. It may also have the same problem on C SDK or the internal C++ component. Could you please fix the WasmEdge_Value related implementation?

@q82419
Copy link

q82419 commented Apr 19, 2024

Hi @hydai @L-jasmine ,

I tested the above WASM with the following C code:

#include <wasmedge/wasmedge.h>
#include <stdio.h>

int main(int Argc, const char* Argv[]) {
  WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL);

  WasmEdge_Value Returns[1];
  WasmEdge_String FuncName = WasmEdge_StringCreateByCString("main");
  WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile(VMCxt, Argv[1], FuncName, NULL, 0, Returns, 1);

  if (WasmEdge_ResultOK(Res)) {
    printf("Get result: %f (0x%016llx 0x%016llx)\n",
      WasmEdge_ValueGetF32(Returns[0]), (uint64_t)(Returns[0].Value >> 64), (uint64_t)(Returns[0].Value));
  } else {
    printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res));
  }

  WasmEdge_VMDelete(VMCxt);
  WasmEdge_StringDelete(FuncName);
  return 0;
}

Which will print the full 128-bit output of value.

And the test for interpreter mode:

$ clang test.c -lwasmedge
$ ./a.out test.wasm
Get result: 1.000000 (0x0000000000000000 0x000000003f800000)

For AOT mode:

$ wasmedgec test.wasm test-aot.wasm
[2024-04-19 20:29:50.112] [info] compile start
[2024-04-19 20:29:50.113] [info] verify start
[2024-04-19 20:29:50.113] [info] optimize start
[2024-04-19 20:29:50.115] [info] optimize done
[2024-04-19 20:29:50.115] [info] codegen start
[2024-04-19 20:29:50.118] [info] output start
[2024-04-19 20:29:50.120] [info] codegen done
[2024-04-19 20:29:50.130] [info] output start
[2024-04-19 20:29:50.130] [info] output done
$ ./a.out test-aot.wasm
Get result: 1.000000 (0x0000000000000000 0x000000003f800000)

And tested both on 0.13.5 and master.
I think the returned value is correct in the WasmEdge C API.

Thanks!

@q82419
Copy link

q82419 commented Apr 19, 2024

Comment:

This occurs on Ubuntu.

Get result: 1.000000 (0x0000000000000000 0x000055503f800000)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants